/**
 * @file EventLoop.hh
 * @author zziywang (zziywang@163.com)
 * @brief { life is too short to learn cpp! }
 * @version 1.0
 * @date 2022-05-07
 *
 * @copyright Copyright (c) 2022
 *
 */

#include "MutexLock.hh"
#include "TcpConnection.hh"
#include <map>
#include <sys/epoll.h>
#include <vector>
using std::map;
using std::vector;

namespace snow
{

using Functor = std::function<void()>;

class Acceptor;
class EventLoop
    : Noncopyable
{
public:
    EventLoop(Acceptor &acceptor);

    void loop();   // 事件循环
    void unLoop(); // 结束循环

    void setConnectionCallBack(const TcpConnectionCallBack &cb);
    void setMessageCallBack(const TcpConnectionCallBack &cb);
    void setCloseCallBack(const TcpConnectionCallBack &cb);

    // v3 新增
    void runInEventLoop(Functor &&cb); // 执行线程池子线程交过来的回调函数

private:
    void epollWait(); // epoll_wait封装
    // epoll_wait返回两种情况：新连接到来；处理信息
    void handleNewConnection();
    void handleMessage(int fd);
    bool isClientQuit(int fd);

    int epollCreate();         // epoll_create，返回epfd
    void epollAddRead(int fd); // 把fd的读事件注册进epoll
    void epollDelRead(int fd); // 把fd的读事件从epoll中删掉

    // v3新增
    int eventfdCreate();
    void eventfdRead();
    void eventfdWrite();
    void doPendingFunctors(); // 执行functors_

private:
    int epfd_;
    // v3新增：通过读写eventfd做线程间通信
    int eventfd_;        // 注册进epoll
    Acceptor &acceptor_; // 引用或指针，--> socketfd和peerfd
    bool isLooping_;
    // 根据fd查找tcp对象 {peerfd: tcp*}
    map<int, TcpConnectionPtr> tcpConns_; // 存指针，避免对象的复制
    vector<struct epoll_event> eventList_;

    // 每个连接都包含三个事件，三个事件应该交给一个连接做处理
    // 以回到函数形式给TCPConnection
    TcpConnectionCallBack onConnectionCb_;
    TcpConnectionCallBack onMessageCb_;
    TcpConnectionCallBack onCloseCb_;

    // v3新增
    // 线程池完成任务后把**send函数**包装成回调，交给I/O线程执行
    vector<Functor> functors_;
    MutexLock mutex_;
};

} // namespace snow